/*
 *  Author: zhaijl 
 *  Url: http://218.1.73.212/down.php
 *  Country: China
 *  
 * ====================================================================
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * ====================================================================
 *
 * This software based apache mina 2.0 and spring 3.0
 *
 */
package org.cloudy.http.codec;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.io.FileInputStream;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.future.WriteFuture;

public class Response {
    public static final int HTTP_STATUS_SUCCESS = 200 ;
    
    public static final int HTTP_STATUS_PARTIAL = 206 ;

    public static final int HTTP_STATUS_NOT_FOUND = 404 ;
    
    public static final int HTTP_STATUS_ERR_SCRIT = 500 ;
    
    public static final int FILE_STATUS_SUCCESS = 0 ;

    private Map< String, String > headers = new HashMap< String, String > () ;

    private IoBuffer body = IoBuffer.allocate ( 256 ) ;
    private int responseCode = HTTP_STATUS_SUCCESS ;
    
    private boolean delivered = false ;
    private boolean buffered = true ;
    
    Request request = null ;
    ByteBuffer bytebuffer = null ;
    FileChannel filechannel = null ;
    WriteFuture writefuture = null ;
    public Response () {
    	body.setAutoExpand ( true ) ;
    }
    
    public Response ( Request request ) {
    	body.setAutoExpand ( true ) ;
    	this.request = request ;
    }
    
    public Request getRequest () {
    	return this.request ;
    }
    
    public void resetBody () {
    	body.clear () ;
    	body.rewind () ;
    }     
    
    public void setWritefuture ( WriteFuture writefuture ) {
    	this.writefuture = writefuture ;
    }
    
    public WriteFuture getWritefuture () {
    	return this.writefuture ;
    } 
    
    public FileChannel getFileChannel ( ) {
    	return this.filechannel ; 
    }      
    
    public FileChannel setFileChannel ( String filepath ) {
    	try {
    		return  ( filechannel = new FileInputStream ( filepath ).getChannel () ) ;
    	} catch ( Exception exc ) {}    	
    	return null ;
    }  
    
    public long filechannelSize () {
    	try {
    		return filechannel.size () ;
    	} catch ( Exception exc ) {
    	}
    	return 0l;
    }
    
    public void filechannelClose () {
    	if ( filechannel == null ) return ;
    	try {
    		filechannel.close () ;
    	} catch ( Exception exc ) {
    	}
    	
    	filechannel = null ;
    }    
    
    public long filechannelPosition () {
    	try {
    		return filechannel.position() ;
    	} catch ( Exception exc ) {
    	}
    	return 0l;
    } 
    
    public void allocate ( int length ) {
    	if ( bytebuffer != null ) {
    		bytebuffer.clear () ;
    		bytebuffer = null ;
    	}
    	bytebuffer = ByteBuffer.allocate ( length ) ;
    } 
    
    public int readBuffer () {
        int read_len = -1 ;
        while ( this.filechannel != null ) {
        	bytebuffer.rewind () ;
        	try {
        		read_len = this.filechannel.read ( bytebuffer ) ;
        	} catch ( Exception exc ) {
        		return -1 ;
        	}         	
        	if ( read_len == 0 ) continue ;
        	break ;
        }
        return read_len ;
	} 
    
    public byte[] bytebufferArray () {
    	if ( bytebuffer != null )
    		return bytebuffer.array () ;
    	return new byte[0] ;
    }    
    
    public boolean isDelivered () {
    	return this.delivered ;
    }
    
    public void delivered ( boolean delivered ) {
    	this.delivered = delivered ;
    }
    
    public boolean isBuffered () {
    	return this.buffered ;
    }
    
    public void buffered ( boolean buffered ) {
    	this.buffered = buffered ;
    }    
    
    public void initialize () {
        headers.put ( "Server", "HttpServer (1.0)" ) ;
        headers.put ( "Cache-Control", "private" ) ;
        headers.put ( "Content-Type", "text/html; charset=iso-8859-1" ) ;
        headers.put ( "Connection", "keep-alive" ) ;
        headers.put ( "Keep-Alive", "true" ) ;
        headers.put ( "Date", new SimpleDateFormat ( "EEE, dd MMM yyyy HH:mm:ss zzz" ).format ( new Date () ) ) ;
        headers.put ( "Last-Modified", new SimpleDateFormat ( "EEE, dd MMM yyyy HH:mm:ss zzz" ).format ( new Date () ) ) ;    	
    }
    
    public void clear () {
    	headers.clear () ;
    }

    public Map< String, String > getHeaders () {
        return headers ;
    }

    public void setContentType ( String contentType ) {
        headers.put ( "Content-Type", contentType ) ;
    }
    
    public void setContentLength ( String contentlength ) {
        headers.put ( "Content-length", contentlength ) ;
    }    
    
    public void setContentRange ( String contentrange ) {
        headers.put ( "Content-range", contentrange ) ;//Content-range:bytes554554-40279979/40279980
    }     

    public void setResponseCode ( int responseCode ) {
        this.responseCode = responseCode ;
    }

    public int getResponseCode () {
        return this.responseCode ;
    }

    public void appendBody ( byte[] b, int off, int len ) {
    	body.put ( b, off, len ) ;
    }
    
    public void appendBody ( byte[] b ) {
    	body.put ( b ) ;
    }    

    public void appendBody ( String s ) {
    	body.put ( s.getBytes () ) ;       
    }

    public IoBuffer getBody() {
        return body ;
    }

    public int getBodyLength () {
        return body.position () ;
    }
    
    public String toString () {
        StringBuilder str = new StringBuilder () ;

        Iterator< Entry< String, String > > it = headers.entrySet ().iterator () ;
        while ( it.hasNext () ) {
        	Entry< String, String > e = ( Entry< String, String > ) it.next () ;
            str.append ( e.getKey () ).append ( " : " ).append ( e.getValue () ).append ( "\n" )  ;
        }
        return str.toString () ;
    }
}
